// Copyright (C) 2025 Kumo inc.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#ifndef ROTHAR_PEGTL_SRC_TEST_PEGTL_VERIFY_RULE_HPP
#define ROTHAR_PEGTL_SRC_TEST_PEGTL_VERIFY_RULE_HPP

#include <cstdlib>
#include <string>

#include <rothar/pegtl/eol.hpp>
#include <rothar/pegtl/memory_input.hpp>
#include <rothar/pegtl/tracking_mode.hpp>
#include <rothar/pegtl/type_list.hpp>

#include "result_type.hpp"
#include "verify_impl.hpp"

namespace rothar
{
   template< typename Rule >
   struct verify_action_impl
   {
      template< typename ActionInput, typename... States >
      static void apply( const ActionInput& /*unused*/, States&&... /*unused*/ )
      {}
   };

   template< typename Rule >
   struct verify_action_impl0
   {
      template< typename... States >
      static void apply0( States&&... /*unused*/ )
      {}
   };

   template< typename Rule, typename Eol = eol::lf_crlf >
   void verify_rule( const std::size_t line, const char* file, const std::string& data, const result_type expected, int remain = -1 )
   {
      if( remain < 0 ) {
         remain = ( expected == result_type::success ) ? 0 : int( data.size() );
      }
      {
         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
         verify_impl_one< Rule, nothing >( line, file, data, in, expected, remain );
         memory_input< tracking_mode::lazy, Eol > i2( data.data(), data.data() + data.size(), file );
         verify_impl_one< Rule, nothing >( line, file, data, i2, expected, remain );
      }
      {
         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
         verify_impl_one< Rule, verify_action_impl >( line, file, data, in, expected, remain );
         memory_input< tracking_mode::lazy, Eol > i2( data.data(), data.data() + data.size(), file );
         verify_impl_one< Rule, verify_action_impl >( line, file, data, i2, expected, remain );
      }
      {
         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
         verify_impl_one< Rule, verify_action_impl0 >( line, file, data, in, expected, remain );
         memory_input< tracking_mode::lazy, Eol > i2( data.data(), data.data() + data.size(), file );
         verify_impl_one< Rule, verify_action_impl0 >( line, file, data, i2, expected, remain );
      }
   }

   template< typename Rule, typename Eol = eol::lf_crlf >
   void verify_only( const std::size_t line, const char* file, const std::string& data, const result_type expected, const std::size_t remain )
   {
      {
         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
         verify_impl_one< Rule, nothing >( line, file, data, in, expected, remain );
      }
      {
         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
         verify_impl_one< Rule, verify_action_impl >( line, file, data, in, expected, remain );
      }
      {
         memory_input< tracking_mode::eager, Eol > in( data.data(), data.data() + data.size(), file, 0, line, 1 );
         verify_impl_one< Rule, verify_action_impl0 >( line, file, data, in, expected, remain );
      }
   }

}  // namespace rothar

#endif
